#ifndef __V4L2CONTROLLER_H__
#define __V4L2CONTROLLER_H__

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <pthread.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#ifdef USE_LIBV4L2
#include <libv4l2.h>
#define IOCTL_VIDEO(fd, req, value) v4l2_ioctl(fd, req, value)
#define OPEN_VIDEO(fd, flags) v4l2_open(fd, flags)
#define CLOSE_VIDEO(fd) v4l2_close(fd)
#else
#define IOCTL_VIDEO(fd, req, value) ioctl(fd, req, value)
#define OPEN_VIDEO(fd, flags) open(fd, flags)
#define CLOSE_VIDEO(fd) close(fd)
#endif

#define NB_BUFFER 4
#define IOCTL_RETRY 3

enum _streaming_state {
    STREAMING_OFF = 0,
    STREAMING_ON = 1,
    STREAMING_PAUSED = 2,
};
typedef enum _streaming_state streaming_state;

typedef struct _V4L2Input V4L2Input;
struct _V4L2Input{
   struct v4l2_jpegcompression jpegcomp;
   pthread_mutex_t db;
   pthread_cond_t db_update;
   unsigned char* buf;
   int size;
   struct timeval timestamp;
};

class V4L2Controller
{
public:
    V4L2Controller();
    ~V4L2Controller();
    int Initialize(const char* device="/etc/video0",
                   int width = 640,
                   int height = 480,
                   int fps = 30,
                   int format = V4L2_PIX_FMT_MJPEG,
                   v4l2_std_id vstd = V4L2_STD_NTSC);
    int GrabUVC();
    int CloseUVC();
    int GetFormat() {return m_format;}
    struct timeval GetTmptimestamp(){return m_tmptimestamp;}
    struct timeval GetFrametimestamp(){return m_frametimestamp;}
    unsigned char* GetTmpBuffer(){return m_tmpbuffer;}
    uint32_t GetTmpBufferUsed(){return m_tmpbytesused;}
    unsigned char* GetFrameBuffer(){return m_framebuffer;}
    int GetFrameSize(){return m_framesize;}

    int GetWidth(){return m_width;}
    int GetHeight(){return m_height;}

private:
    int EnableVideo();
    int DisableVideo(streaming_state disabledState = STREAMING_OFF);
    int XIOCtl(int IOCTL_X, void* arg);

    char m_videodevice[16];
    int m_width;
    int m_height;
    int m_fps;
    int m_format;
    int m_vstd;
    int m_fd;
    int m_framesize;
    struct timeval m_tmptimestamp;
    struct timeval m_frametimestamp;
    uint32_t m_tmpbytesused;
    void *m_mem[NB_BUFFER];
    unsigned char* m_tmpbuffer;
    unsigned char* m_framebuffer;
    streaming_state m_streamingState;
};

#endif
